/**
 * javascript代码自动提示插件，跟eclipse等开发工具提示效果一样
 * @param $.autocode
 */
(function($) {
	$.fn.extend({
		"autocode" : function(options) {
			var opts = $.extend({}, defaluts, options);
			var that = this;
			this.after($("<div class=\"js-coding-tips\">"));
			var tips = this.nextAll(".js-coding-tips");
			var currIndex = -1;
			var x, y;
			var codeMapping = mapping(window, []);
			this.on("input", autocoding);
			$(document).on("keyup", moveTips);
			tips.on("mouseover", "li", function() {
				tips.find("li").removeClass("over");
				$(this).addClass("over");
			}).on("click", "li", function() {
				appendJSCodingWith(that,this);
			}).on("dblclick","li",function(){
				var source = $(this).data("source");
				window.open("http://www.baidu.com/s?wd=javascript "+source);
			})
			function moveTips(e) {
				var event = e || window.event;
				var code = event.keyCode;
				var curr = tips.find("li.over");
				if (curr.length > 0) {
					currIndex = curr.index();
				}
				var len = tips.find("li").length;
				if (code == 38) {// 上移
					currIndex--;
					if (currIndex < 0) {
						currIndex = len - 1;
					}
				} else if (code == 40) {// 下移
					currIndex++;
					if (currIndex >= (len))
						currIndex = 0;
				} else {
					return;
				}
				tips.find("li").removeClass("over");
				var scrollTo = tips.find("li:eq(" + currIndex + ")");
				scrollTo.addClass("over");
				var container = tips.find("ul");
				var top = scrollTo.offset().top - container.offset().top + container.scrollTop();
				container.animate({scrollTop:top},100);
			}
			this.matchHigh = function(text,source){
				if(opts.matchHigh){
					return opts.matchHigh(text,source);
				}
				return text.replace(source,"<strong class=\"code_high\">"+source+"</strong>");
			}
			function autocoding(e) {
				tips.hide();
				var val = that.val();
				var code = splitLast(val, " ");
				if (!isEmpty(code)) {
					code = splitLast(code, ".");
					code = $.trim(code);
				} else {
					return;
				}
				var codings = executionFrom(code);
				if (codings.length < 1) {
					codings = search(codeMapping, code);
				}
				if (codings.length < 1)
					return;
				loaderJSCodingTips(codings,code);
			}
			function loaderJSCodingTips(codings,code) {
				codings.sort();
				var ul = $("<ul class=\"js-coding-list\">");
				if (tips.find(".js-coding-list").length > 0) {
					ul = tips.find(".js-coding-list");
				} else {
					tips.append(ul);
				}
				ul.empty();
				$.each(codings, function() {
					ul.append($("<li data-source=\""+this+"\" title=\"双击了解此关键字更多相关信息\" data-match=\""+code+"\">" + that.matchHigh(this,code) + "</li>"));
				})
				setPosition(tips,that);
				tips.animate({
					opacity : "show"
				}, "slow");
				return ul;
			}
			function splitLast(str, split) {
				str = "" + str;
				var last = str.split(split);
				var index = last.length - 1;
				var match = last[index];
				if(isEmpty(match))match = last[index-1];
				return match;
			}
			function executionFrom(str) {
				var props = [];
				try {
					var ele = eval(str);
					$.each(ele, function(prop) {
						props.push(prop);
					});
				} catch (e) {
				}
				;
				return props;
			}
			function mapping(ele, array) {
				$.each(ele, function(prop) {
					var attr = prop;
					if (isObject(prop)) {
						mapping(ele, array);
						return true;
					}
					array.push(prop);
				});
				return array;
			}
			function isObject(o) {
				return (o instanceof Object);
			}
			function search(array, str) {
				var i = array.length;
				var ele = [];
				while (i--) {
					if (startWith(array[i], str) && array[i]!=str) {
						ele.push(array[i]);
					}
				}
				return ele;
			}
			function isEmpty(str) {
				return str == "" || str.length == 0;
			}
			function setPosition(tips, ele) {
	            var position = textareaSelectionPosition(ele),
                lineHeight = parseInt(ele.css('line-height'), 10) || 25;
	            tips.css('left', position.left+10);
	            tips.css('top', lineHeight + position.top);
	            var eleRight = ele.offset().left + ele.width(),
	                tipsRight = tips.offset().left + tips.width();
	            if (eleRight <= tipsRight) {
	                tips.css('left', Math.abs(tips.position().left - (tipsRight - eleRight)));
	            }
	        }
			function textareaSelectionPosition($el) {
	            var a, b, c, d, e, f, g, h, i, j, k;
	            if (!(i = $el[0])) return;
	            if (!$(i).is("textarea")) return;
	            if (i.selectionEnd == null) return;
	            g = {
	                position: "absolute",
	                overflow: "auto",
	                whiteSpace: "pre-wrap",
	                wordWrap: "break-word",
	                boxSizing: "content-box",
	                top: 0,
	                left: -9999
	              }, h = ["boxSizing", "fontFamily", "fontSize", "fontStyle", "fontVariant", "fontWeight", "height", "letterSpacing", "lineHeight", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop", "textDecoration", "textIndent", "textTransform", "width", "word-spacing"];
	            for (j = 0, k = h.length; j < k; j++) e = h[j], g[e] = $(i).css(e);
	            return c = document.createElement("div"), $(c).css(g), $(i).after(c), b = document.createTextNode(i.value.substring(0, i.selectionEnd)), a = document.createTextNode(i.value.substring(i.selectionEnd)), d = document.createElement("span"), d.innerHTML = "&nbsp;", c.appendChild(b), c.appendChild(d), c.appendChild(a), c.scrollTop = i.scrollTop, f = $(d).position(), $(c).remove(), f
	        }
			function startWith(str, s) {
				if (isEmpty(s))
					return false;
				var temp = s;
				if (s.length > str.length) {
					s = str;
					str = temp;
				}
				return new RegExp("^" + s + "", "ig").test(str);
			}
			function appendJSCodingWith(obj, li) {
				var code = $(li);
				var text = code.data("source");
				var dthis = obj[0];
				var match = code.data("match");
				if(dthis.selectionStart){
					var start = dthis.selectionStart; 
					var end = dthis.selectionEnd;
					var source = dthis.value;
					if(start==end){
						source = source.substring(end-match.length,end);
						if(source != match){
							start = end-1;
							if(dthis.value.substring(start,end)==".")
								text = "."+text;
						}else{
							start = end-match.length;
						}
					}
					dthis.value = dthis.value.substring(0, start) + text + dthis.value.substring(end, dthis.value.length);
					tips.hide();
				}
				dthis.focus();
			}
		}
	});
	var defaluts = {
			matchHigh:null
	};
	return this;
})(window.jQuery);